#pragma once
#ifndef ELLIPSE_H
#define ELLIPSE_H

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// 256位数据定义方便编写代码
typedef uint64_t sm2_uint256_64t[4];
typedef uint64_t sm2_uint512_64t[8];
typedef uint64_t sm2_uint128_t[2];
typedef uint32_t sm2_uint256_t[8];

typedef uint32_t sm2_uint512_t[16];

// 椭圆曲线点表示，使用字节数组存储点坐标（大整数表示）。
typedef struct
{
    uint32_t x[8]; // x 坐标，32字节（256位）
    uint32_t y[8]; // y 坐标，32字节（256位）
    uint32_t z[8]; // 投影坐标是三维
} sm2_point_t;

typedef struct
{
    uint64_t x[4]; // x 坐标，32字节（256位）
    uint64_t y[4]; // y 坐标，32字节（256位）
    uint64_t z[4]; // 投影坐标是三维
} sm2_point_64t;

extern const sm2_uint256_t Prime;
extern const uint8_t param_A[32];
extern const uint8_t param_B[32];
extern const sm2_point_t mg_G;
extern const sm2_uint256_t param_N;
extern const sm2_uint256_t N_256_ZERO;
extern const sm2_uint256_t N_256_1;
extern sm2_uint256_t num_3;
extern sm2_uint256_t N_ONE_MOD_n;

extern const sm2_uint256_64t Prime_64;
extern const sm2_uint256_64t param_A_64;
extern const sm2_point_64t param_G_64;
extern const sm2_point_64t mg_G_64;
extern const sm2_uint256_64t param_N_64;
extern const sm2_uint256_64t N_256_ZERO_64;
extern const sm2_uint256_64t N_256_1_64;
extern sm2_uint256_64t num_3_64;
extern sm2_uint256_64t N_ONE_MOD_n_64;
extern sm2_uint256_t N_THREE;
extern sm2_uint256_64t N_THREE_64;
extern const sm2_uint256_64t mg_A_64;
extern const sm2_uint256_t mg_A;
extern const uint64_t N_2_512_mod_p_64[4];
// 类型转换函数
void convert_uint8_to_uint64(uint8_t src[32], uint64_t dst[4]);
void convert_uint64_to_uint8(uint64_t src[4], uint8_t dst[32]);
void convert_to_uint32(uint8_t src[32], uint32_t dst[8]);
void convert_to_uint8(uint32_t src[8], uint8_t dst[32]);
void sm2_getlow256(sm2_uint512_t src, sm2_uint256_t dst);
void sm2_gethigh256(sm2_uint512_t src, sm2_uint256_t dst);

void num2mgmy_modp_64(uint64_t src[4], sm2_uint256_64t p, uint64_t dst[4]);
void num2mgmy_modn_64(uint64_t src[4], sm2_uint256_64t p, uint64_t dst[4]);
void mgmy2num_modp_64(uint64_t src[4], sm2_uint256_64t p, uint64_t dst[4]);
void mgmy2num_modn_64(uint64_t src[4], sm2_uint256_64t p, uint64_t dst[4]);
void point_modp2mgmy(sm2_point_t* src, sm2_uint256_t p, sm2_point_t* dst); 
void mgmy_modp2point(sm2_point_t* src, sm2_uint256_t p, sm2_point_t* dst); 
void mgmy_modp2point_64(sm2_point_64t* src, sm2_uint256_64t p, sm2_point_64t* dst);

// 有限域操作函数
void neg_p(sm2_uint256_t result, const sm2_uint256_t p); // 计算2^256-p 用于溢出处理
int compare_value(sm2_uint256_t a, sm2_uint256_t b);  // 比较2个256位数的大小关系
void copy(sm2_uint256_t src, sm2_uint256_t dst); // 复制数据
void demo_point_multiply_64(sm2_point_64t* P, sm2_uint256_64t k, sm2_uint256_64t p, sm2_point_64t* R);
uint32_t add(sm2_uint256_t a, sm2_uint256_t b, sm2_uint256_t result);
uint32_t add_uint512_t(sm2_uint512_t a, sm2_uint512_t b, sm2_uint512_t result);
uint64_t add_uint512_64t(sm2_uint512_64t a, sm2_uint512_64t b, sm2_uint512_64t result);
void mod_add(sm2_uint256_t a, sm2_uint256_t b, sm2_uint256_t p, sm2_uint256_t result); // 有限域加法 (a + b) mod p
uint32_t sub(sm2_uint256_t a, sm2_uint256_t b, sm2_uint256_t result);
void mod_sub(sm2_uint256_t a, sm2_uint256_t b, sm2_uint256_t p, sm2_uint256_t result);   // 有限域减法 (a - b) mod p
void mod_mul(sm2_uint256_t a, sm2_uint256_t b, sm2_uint256_t p, sm2_uint256_t result); // 有限域乘法 (a * b) mod p
void mod_fast_exp(sm2_uint256_t a, uint32_t b, sm2_uint256_t p, sm2_uint256_t result);
void mod_sqr(sm2_uint256_t a, sm2_uint256_t p, sm2_uint256_t result);     // 有限域平方 (a^2) mod p
void mod_inverse(sm2_uint256_t a, sm2_uint256_t p, sm2_uint256_t result);      // 有限域逆元 a^-1 mod p
void mod_sub_64(sm2_uint256_64t a, sm2_uint256_64t b, sm2_uint256_64t p, sm2_uint256_64t result);
void montgomery_multiplication_modn_64_32(uint64_t* A, uint64_t* B, uint64_t* p, uint64_t* R);
void montgomery_multiplication_modp_64_32(uint64_t* A, uint64_t* B, uint64_t* p, uint64_t* R);
void mod_sqr_modp_64(sm2_uint256_64t a, sm2_uint256_64t p, sm2_uint256_64t result);
void mod_sqr_modn_64(sm2_uint256_64t a, sm2_uint256_64t p, sm2_uint256_64t result);
void mod_add_64(sm2_uint256_64t a, sm2_uint256_64t b, sm2_uint256_64t p, sm2_uint256_64t result);
void mod_fast_exp_modp_64(sm2_uint256_64t a, uint64_t b, sm2_uint256_64t p, sm2_uint256_64t result);
void mod_fast_exp_modn_64(sm2_uint256_64t a, uint64_t b, sm2_uint256_64t p, sm2_uint256_64t result);
void mod_sqr_modp_64(sm2_uint256_64t a, sm2_uint256_64t p, sm2_uint256_64t result);
void mod_sqr_modn_64(sm2_uint256_64t a, sm2_uint256_64t p, sm2_uint256_64t result);
void mod_inverse_modp_64(sm2_uint256_64t a, sm2_uint256_64t p, sm2_uint256_64t result);
void mod_inverse_modn_64(sm2_uint256_64t a, sm2_uint256_64t p, sm2_uint256_64t result);
uint64_t sub_64(sm2_uint256_64t a, sm2_uint256_64t b, sm2_uint256_64t result);
uint64_t add_64(sm2_uint256_64t a, sm2_uint256_64t b, sm2_uint256_64t result);
uint64_t add_128(sm2_uint128_t a, sm2_uint128_t b, sm2_uint128_t result);
static uint64_t is_zero(uint64_t in);
uint64_t sm2_uint256t_is_zero(const sm2_uint256_64t a);
void sm2_uint256t_copy(sm2_uint256_64t a, sm2_uint256_64t r);
void sm2_uint256t_set_zero(sm2_uint256_64t r);
bool is_in_N(uint64_t* r);

// 椭圆曲线点运算函数
void point_inverse_64(const sm2_point_64t* a, sm2_uint256_64t p, sm2_point_64t* r);
void point_add(const sm2_point_t* a, const sm2_point_t* b, sm2_uint256_t p, sm2_point_t* r); // 点加法 a + b= r
void point_double(const sm2_point_t* P, sm2_uint256_t p, sm2_point_t* r);                    // 点倍加 2P = R
void point_multiply(sm2_point_t* P, sm2_uint256_t k, sm2_uint256_t p, sm2_point_t* R);  // 标量乘法 k * P = R
void point_inverse_64(const sm2_point_64t* a, sm2_uint256_64t p, sm2_point_64t* r);
sm2_point_64t Crypto_ECC_wNAF_scalar_multiply(sm2_point_64t P, sm2_uint256_64t k, int w);
void Crypto_ECC_jacobi_to_affine_64(sm2_uint256_64t x, sm2_uint256_64t y, sm2_uint256_64t z, sm2_uint256_64t p, sm2_point_64t* r);
void Crypto_ECC_jacc_point_add_64(sm2_point_64t* a, sm2_point_64t* b, sm2_uint256_64t p, sm2_point_64t* r);
void Crypto_ECC_jacc_point_double_64(const sm2_point_64t* a, sm2_uint256_64t p, sm2_point_64t* r);

// 调试和打印工具
void print_point(const sm2_point_t* P); // 打印点坐标
void print_uint32_array(uint32_t arr[8]);  // 打印uint32数组
void print_uint8_array(uint8_t arr[32]); // 打印uint8数组
void print_uint512_array(sm2_uint512_t arr); // 打印512位数据
void print_uint64_array(uint64_t arr[4]);
void print_uint128(uint64_t arr[2]);
void print_sm2_uint256_t(sm2_uint256_t num);
void print_point_64(sm2_point_64t* Point);

#endif // ELLIPSE_H
